-- i_left |**| (2 ^` i_right)

-- drop function if exists sm_sc.fv_gemm_power2_2nd_ops_int_py(float[], int[], float[]);
create or replace function sm_sc.fv_gemm_power2_2nd_ops_int_py
(
  i_left      float[]
, i_right     int[]      --  相当于 2 ^ sm_sc.fv_gemm_power2_3ops() 第二个参数
, i_bias      float[]   default null
)
returns float[]
as
$$
  import numpy as np
  v_left = np.float64(i_left)
  v_right = np.int8(i_right)
  v_bias = np.float64(i_bias)
  v_ret = np.zeros([v_left.shape[-2], v_right.shape[-1]])
  
  for i in range(0, v_left.shape[-2]) :
    for k in range(0, v_right.shape[-1]) :
      v_ret[i, k] = np.ldexp(v_left[i, :], v_right[:, k]).sum()
  
  if i_bias is None :
    return v_ret.tolist()
  else :
    return (v_ret + v_bias).tolist()
$$
language plpython3u stable
parallel safe
;

-- select 
--   sm_sc.fv_gemm_power2_2nd_ops_int_py
--   (
--     array[[1, 2, 3], [1, 2, 3]] :: float[]
--   , array[[1, 2], [3, 1], [2, 3]]
--   )

-- select 
--   sm_sc.fv_gemm_power2_2nd_ops_int_py
--   (
--     array[[1, 2, 3], [1, 2, 3]] :: float[]
--   , array[[1, 2], [3, 1], [2, 3]]
--   , array[[1, 2], [3, 1]]
--   )